package com.ylyq.ylxx.util;

import cn.novelweb.video.edit.VideoEditing;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.lang3.StringUtils;
import org.bytedeco.ffmpeg.ffmpeg;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.*;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @ClassName FfmpegUtil
 * @Description TODO
 * @Author xiaweichao
 * @Date 2020/9/3 18:04
 * @Version 1.0
 */
public class FfmpegUtil {

    private static String ffmpegPath = "C:\\ffmpeg.exe";// 此处是配置地址，可自行写死如“D:\\ffmpeg\\ffmpeg.exe”
//    private static String ffmpegPath = "D:\\temp\\ffmpeg\\bin\\ffmpeg.exe";

    /**
     * 拼接视频文件
     *
     * @param videoPathList
     */
    public static String mergeVideo(List<String> videoPathList, String targetPath) {
        if (videoPathList.size() > 1) {

//            String ffmpegPath = CaptureConfig.getFfmpegPath();// 此处是配置地址，可自行写死如“D:\\ffmpeg\\ffmpeg.exe”
//            String ffmpegPath = ffmpegPath;// 此处是配置地址，可自行写死如“D:\\ffmpeg\\ffmpeg.exe”
//            String ffmpegPath = "D:\\temp\\ffmpeg\\bin\\ffmpeg.exe" ;
            String txtPath = "";
            try {
                int index = videoPathList.get(0).lastIndexOf(".");
//                String newMergePath = videoPathList.get(0).substring(0, index) + "new" + videoPathList.get(0).substring(index, videoPathList.get(0).length());
                String newMergePath = StringUtils.isBlank(targetPath) ? "C:\\uploads\\mergeVideo\\" + Tools.getCurrentDate() + videoPathList.get(0).substring(index, videoPathList.get(0).length()) : targetPath;
                txtPath = videoPathList.get(0).substring(0, index) + ".txt";
                FileOutputStream fos = new FileOutputStream(new File(txtPath));
                for (String path : videoPathList) {
                    fos.write(("file '" + path + "'\r\n").getBytes());
                }
                fos.close();

                StringBuffer command = new StringBuffer("");
                command.append(ffmpegPath);
                command.append(" -f");
                command.append(" concat");
                command.append(" -safe");
                command.append(" 0");
                command.append(" -i ");
                command.append(txtPath);
                command.append(" -c");
                command.append(" copy ");// -c copy 避免解码，提高处理速度
                command.append(newMergePath);

                start(command.toString());

                // 删除产生的临时用来存放每个视频文件路径的txt文件
                File txtFile = new File(txtPath);
                txtFile.delete();

                // 删除原视频文件
//                for (String filePath : videoPathList){
//                    File file = new File(filePath);
//                    file.delete();
//                }

                // 合成的新视频文件重命名为原视频文件的第一个文件名
//                File newFile = new File(newMergePath);
//                File oldFile = new File(videoPathList.get(0));
//                newFile.renameTo(oldFile);
                return newMergePath;
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    /**
     * @return java.lang.String
     * @Author xiaweichao
     * @Description //TODO 给视频添加背景音乐 * @Date 18:58 2020/9/8
     * @Param [videoPathList, targetPath]
     **/
    public static String mergeVideoAndAudio(String videoPath, String audioPath, String targetPath) {
        try {
            File file = new File(targetPath);

            if (!file.getParentFile().exists()) {
                if (!file.getParentFile().mkdirs()) {
                    System.out.println(
                            "- ERROR creating output directory '" + file.getParentFile().getAbsolutePath() + "'");
                }
            }
            double videoTime = getVideoTime(videoPath, ffmpegPath);
            //添加背景音乐指令
//            start(ffmpegPath + " -i " + audioPath + " -i " + videoPath + " -t " + videoTime + " -filter_complex amix=inputs=2  " + targetPath);
//            convertor1(videoPath,audioPath , videoTime , targetPath);

            convertor(videoPath,audioPath , videoTime , targetPath);

            return targetPath;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    private static void start(String command) {
        try {
            final Process process = Runtime.getRuntime().exec(command);
            //⚠️此处代码是因为如果合并大视频文件会产生大量的日志缓存导致线程阻塞，最终合并失败，所以加两个线程处理日志的缓存，之后再调用waitFor方法，等待执行结果。
            new Thread() {
                @Override
                public void run() {
                    BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
                    String line = null;
                    try {
                        while ((line = in.readLine()) != null) {
//                            System.out.println("output:" + line);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            in.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();

            new Thread() {
                @Override
                public void run() {
                    BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                    String line = null;
                    try {
                        while ((line = err.readLine()) != null) {
//                            System.out.println("err:" + line);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            err.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();

            // 等待命令子线程执行完成
            process.waitFor();
            process.destroy();

        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void convertor(String videoInputPath, String mp3InputPath, double seconds, String videoOutputPath) throws Exception {

        StringBuilder stringBuilder=new StringBuilder();
        stringBuilder.append(ffmpegPath);
        stringBuilder.append(" -i ");
        stringBuilder.append(mp3InputPath);
        stringBuilder.append(" -i ");
        stringBuilder.append(videoInputPath);
        stringBuilder.append(" -t ");
        stringBuilder.append(seconds);
        stringBuilder.append(" -filter_complex amix=inputs=2 ");
        stringBuilder.append(videoOutputPath);

        start(stringBuilder.toString());
    }
    public static void convertor1(String videoInputPath, String mp3InputPath, double seconds, String videoOutputPath) throws Exception {
//		ffmpeg.exe -i 视频.mp4 -i bgm.mp3 -t 7 -y 新的视频.mp4
        List<String> command = new ArrayList<>();
        command.add(ffmpegPath);

        command.add("-i");
        command.add(videoInputPath);

        command.add("-i");
        command.add(mp3InputPath);

        command.add("-t");
        command.add(String.valueOf(seconds));

//        command.add("-y");
//        command.add("-filter_complex amix=inputs=2");

        command.add("-filter_complex");
        command.add("amix=inputs=2:duration=first:dropout_transition=2");

        command.add(videoOutputPath);

        ProcessBuilder builder = new ProcessBuilder();
        builder.command(command);
        final Process p = builder.start();

        //从输入流中读取视频信息
        BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
        StringBuffer sb = new StringBuffer();
        String line = "";
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
    }

    /**
     * 获取视频总时间
     *
     * @param ffmpeg_path ffmpeg路径
     * @return
     */
    public static double getVideoTime(String video_path, String ffmpeg_path) {
        List<String> commands = new java.util.ArrayList<String>();
        commands.add(ffmpeg_path);
        commands.add("-i");
        commands.add(video_path);
        try {
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(commands);
            final Process p = builder.start();

            //从输入流中读取视频信息
            BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            StringBuffer sb = new StringBuffer();
            String line = "";
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            br.close();

            //从视频信息中解析时长
            String regexDuration = "Duration: (.*?), start: (.*?), bitrate: (\\d*) kb\\/s";
            Pattern pattern = Pattern.compile(regexDuration);
            Matcher m = pattern.matcher(sb.toString());
            if (m.find()) {
                double time = getTimelen(m.group(1));
                System.out.println(video_path + ",视频时长：" + time + ", 开始时间：" + m.group(2) + ",比特率：" + m.group(3) + "kb/s");
                return time;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return 0;
    }

    //格式:"00:00:10.68"
    private static double getTimelen(String timelen) {
        double min = 0;
        String strs[] = timelen.split(":");
        if (strs[0].compareTo("0") > 0) {
            min += Integer.valueOf(strs[0]) * 60 * 60;//秒
        }
        if (strs[1].compareTo("0") > 0) {
            min += Integer.valueOf(strs[1]) * 60;
        }
        if (strs[2].compareTo("0") > 0) {
            min += Float.valueOf(strs[2]);
        }
        return min;
    }

    public static void main(String[] args) {

        long begin = System.currentTimeMillis();

//         合并视频文件
//        List videoPathList = new ArrayList<>();
//        videoPathList.add("D:\\temp1\\1.mp4");
//        videoPathList.add("D:\\temp1\\2.mp4");
//        videoPathList.add("D:\\temp1\\3.mp4");
//        videoPathList.add("D:\\temp1\\4.mp4");
//        videoPathList.add("D:\\temp1\\5.mp4");
//        videoPathList.add("D:\\temp1\\6.mp4");
//        String mergeVideoPath = Mp4ParserUtils.mergeVideo(videoPathList,"D:\\temp1\\output11111.mp4");

//        StringBuilder videots = new StringBuilder();
//        for (int i = 0; i < videoPathList.size(); i++) {
//            start(ffmpegPath + " -i " + videoPathList.get(i) + " -vcodec copy -acodec copy -vbsf h264_mp4toannexb D:\\temp1\\" + i + ".ts");
//            videots.append(i + ".ts|");
//        }
//        String command = ffmpegPath + " -i \"concat:" + videots.substring(0, videots.length() - 1) + "\" -acodec copy -vcodec copy -absf aac_adtstoasc D:\\temp1\\output1.mp4";
//
//        start(command);
//
//        // 删除原视频文件
//        for (int i = 0; i < videoPathList.size(); i++) {
//            File file = new File("D:\\temp1\\" + i + ".ts");
//            file.delete();
//        }


//
//        mergeVideo(videoPathList,"D:\\temp1\\output321.mp4");
////        VideoParameters
////        VideoEditing.

        try {

            //这两条指令都可以无损无bug合成音乐+视频
//            start("D:\\temp\\ffmpeg\\bin\\ffmpeg.exe -i D:\\temp\\mmm.mp4 -i D:\\temp\\a.mp3 -filter_complex amix=inputs=2:duration=first:dropout_transition=2 D:\\temp\\output112.mp4");
//            start("D:\\temp\\ffmpeg\\bin\\ffmpeg.exe -i D:\\temp\\a.mp3 -i D:\\temp\\mmm.mp4 -t 13 -filter_complex amix=inputs=2  D:\\temp\\output4.mp4");


//            start("D:\\temp\\ffmpeg\\bin\\ffmpeg.exe -i D:\\temp\\mmm.mp4 -i D:\\temp\\a.mp3 -lavfi hstack=inputs=2 D:\\temp\\output1.mp4");

//            start("D:\\temp\\ffmpeg.exe -i D:\\temp\\mmm.mp4 -i D:\\temp\\a.mp3 -c:v copy -c:a aac -strict experimental D:\\temp\\new1.mp4");

//            start("C:\\ffmpeg.exe -f concat -safe 0 -i D:\\temp\\convert.txt -c copy D:\\temp\\output.mp4");


//            start("C:\\ffmpeg.exe -i D:\\temp\\mmm.mp4 -c:v copy -an  D:\\temp\\input-no-audio.mp4");
//            start("C:\\ffmpeg.exe -i D:\\temp\\input-no-audio.mp4 -i D:\\temp\\a.mp3 -t 11 -y D:\\temp\\new.mp4");

//            start("D:\\temp\\ffmpeg.exe -i D:\\temp\\mmm.mp4 -i D:\\temp\\a.mp3 -y D:\\temp\\new2.mp4");


//            double videoTime = getVideoTime("D:\\temp\\mmm.mp4",
//                    "D:\\temp\\ffmpeg\\bin\\ffmpeg.exe");
//            start("D:\\temp\\ffmpeg\\bin\\ffmpeg.exe -i D:\\temp\\a.mp3 -i D:\\temp\\mmm.mp4 -t "+videoTime+" -filter_complex amix=inputs=2  D:\\temp\\output5.mp4");

//             convertor1("D:\\temp\\mmm.mp4", "D:\\temp\\a.mp3",13, "D:\\temp\\new12266.mp4");

            mergeVideoAndAudio("D:\\temp\\mmm.mp4", "D:\\temp\\a.mp3", "D:\\temp\\output8.mp4");
        } catch (Exception e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println(end - begin);
    }
}
